﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using FlatRedBall;
using FlatRedBall.Graphics;
using FlatRedBall.Math.Geometry;
using Microsoft.Xna.Framework;
using Rvz.Game.Main.Common;
using Rvz.Game.Main.State;

namespace Rvz.Game.Main.Entities
{
    public abstract class EntityBase<TEntity, TState> : PositionedObject
        where TEntity : EntityBase<TEntity, TState>
        where TState : IEntityState<TEntity>
    {
        protected readonly string ContentManagerName;

        protected virtual float Scale { get { return 1f; } }
        protected virtual Sprite VisibleRepresentation { get; set; }
        protected abstract string SpriteFileLocation { get; }

        public virtual Circle CollisionShape { get; protected set; }

        protected EntityBase(string contentManagerName)
        {
            ContentManagerName = contentManagerName;
            AddToManagers(null);
        }

        public virtual void AddToManagers(Layer layerToAddTo)
        {
            // Add the Entity to the SpriteManager
            // so it gets managed properly (velocity, acceleration, attachments, etc.)
            SpriteManager.AddPositionedObject(this);

            AddSprite();
            AddCollision();
        }

        public virtual void StopAllMovement()
        {
            XVelocity = 0;
            YVelocity = 0;
        }

        private readonly Queue<TState> _states = new Queue<TState>();
        public virtual IEnumerable<TState> States
        {
            get { return _states.ToArray(); }
        }

        public virtual void AddState(TState state)
        {
            _states.Enqueue(state);
        }

        public virtual void ClearStates()
        {
            _states.Clear();
        }

        public virtual void ProcessStates(GameState gameState)
        {
            States.ForEach(x =>
                               {
                                   var queuedState = _states.Dequeue();
                                   queuedState.ProcessState((TEntity)this, gameState);
                               });
        }

        /// <summary>
        /// Here you may want to add your objects to the engine.  Use layerToAddTo
        /// when adding if your Entity supports layers.  Make sure to attach things
        /// to the current class if appropriate.
        /// </summary>
        protected virtual void AddSprite()
        {
            VisibleRepresentation = SpriteManager.AddSprite(SpriteFileLocation, ContentManagerName);
            VisibleRepresentation.AttachTo(this, false);
            VisibleRepresentation.ScaleX = Scale;
            VisibleRepresentation.ScaleY = Scale;
        }

        protected virtual void AddCollision()
        {
            CollisionShape = ShapeManager.AddCircle();
            CollisionShape.Radius = CollisionShape.Radius * Scale;
            CollisionShape.AttachTo(this, false);
            CollisionShape.Visible = false;
        }

        public virtual void HandleUpdate(GameState gameState, GameTime gameTime)
        {
        }

        public virtual void Destroy()
        {
            // Remove self from the SpriteManager:
            SpriteManager.RemovePositionedObject(this);
            SpriteManager.RemoveSprite(VisibleRepresentation);
            ShapeManager.Remove(CollisionShape);
        }
    }
}
